---------------------------------------------------------------------- ---------------------------------------------------------------------- DOCUMENT: PROGRAMMING DMA I/O WITH VMDMA Version 1.0 March 8, 1991 Programming and Documentation by Ryan Hanlon Copyright (c) 1991, Covox, Inc. All Rights Reserved ---------------------------------------------------------------------- GENERAL DESCRIPTION The recording and playback of non-compressed 8 bit PCM sound data via DMA (memory to port, port to memory), can be achieved by setting the Voice Master card and mother board DMA controller properly. This document will supply all of the raw information you will need to write recording and playback software for the Voice Master and the Sound Master II boards. The Voice Master is only capable of being set to use IRQ 3 or IRQ 7 while the Sound Master II board can use any one of IRQ's 3 through 7. Both the Voice Master and the Sound Master II were designed to use DMA channel 1 or channel 3 and one of the port ranges starting at 0x0220, 0x0240, 0x0280, or 0x02C0. NOTE : Except for the IRQ changes on the Sound Master II the functionality of the Voice Master is replicated on the Sound Master II board. For the duration of this document all references to the Voice Master (VMDMA), apply equally to the Sound Master II board. This document should be used in conjunction with the document and source code supplied with the program sm2detec.exe. ---------------------------------------------------------------------- VOICE MASTER PORTS BASE PORTS Jumper setting positions 1 through 4 determine the BASE PORT of the Voice Master. 0x0220 to 0x022F, 0x0240 to 0x024F, 0x0280 to 0x028F, 0x02C0 to 0x02CF BASE PORT OFFSETS The BASE PORT plus (+) the BASE PORT OFFSET can be used to access the ports on the Voice Master. As can be seen below only port offsets from 0x08 and 0x0F are used on the Voice Master. 8254 TIMER 0 OFFSET = 0x08 Timer/Clock 8254 TIMER 1 OFFSET = 0x09 Timer/Clock 8254 TIMER 2 OFFSET = 0x0A Timer/Clock 8254 CONTROL OFFSET = 0x0B Timer/Clock control register CLEAR IRQ OFFSET = 0x0C \ DISABLE VMDMA OFFSET = 0x0D > VMDMA Control ports ENABLE VMDMA OFFSET = 0x0E / DAC OFFSET = 0x0F The DAC OFFSET port should not be written to during DMA i/o. ---------------------------------------------------------------------- VMDMA CONTROL PORT OFFSETS DISABLE DMA OFFSET = 0x0D Writing to this port will disable DREQ (DMA Request), channel 1 or DREQ channel 3 thus preventing all VMDMA i/o. ENABLE DMA OFFSET = 0x0E Writing to this port should be done last and only after all clock and DMA setup has been completed. A write to this port will fire off a DREQ (cause the DREQ line to go low), thus allowing the VMDMA i/o to begin. CLEAR IRQ OFFSET = 0x0C This BASE PORT offset is to be utilized after every DMA terminal count is reached. It is common to find this port being written to inside an interrupt handler. Any value may be output to the port. ---------------------------------------------------------------------- INTEL 8254 COUNTER/TIMER ONBOARD THE VOICE MASTER The Voice Master is equipped with the Intel 8254 programmable interval counter/timer. COUNTER 2 is used for DMA i/o control. COUNTER 1 and 3 are not used by the Voice Master and are available for general purpose use within software. TIMER 0 OFFSET = 0x08 TIMER 1 OFFSET = 0x09 TIMER 2 OFFSET = 0x0A 8254 CONTROL OFFSET = 0x0B COUNTER 2 is setup to fire off DREQ's at given intervals by latching to the 8254 CONTROL OFFSET port in LSB/MSB order. The formula you will need to properly program this DREQ frequency is shown below. 7.1MHz i/o rate = ------------ where N is a 16 bit divisor that N is written, 8 bits at a time, to one of the TIMER OFFSETs. Each DREQ sent by the Voice Master is received by the 8237 DMA controller on the mother board. After one 8 bit DMA read or write is performed the 8237 sends a DACK (DMA Acknowledged), signal to the Voice Master board. This DACK signal effectively disables the Voice Master from sending another DREQ to the 8237 until CLOCK 2 reaches zero again. Bit settings for the CONTROL port of the 8254. bits 7,6 = 00 timer 0 bits 5,4 = 00 latch preset 01 timer 1 01 read/write only MSB 10 timer 2 10 read/write only LSB 01 read/write LSB, then MSB bits 3,1 = 000 mode 0 bit 0 = 0 binary 001 mode 1 1 BCD decrementing 010 mode 2 011 mode 3 100 mode 4 101 mode 5 ---------------------------------------------------------------------- 8237 DMA CONTROLLER ON THE MOTHERBOARD The DMA on the mother board should be completely setup for i/o only after the Voice Master board has had the DREQ lines disabled. (See DISABLE VMDMA OFFSET for more information). The recommended settings for performing recording or playback are as follows : 1. single mode 2. address increment 3. no automatic reinitialize 4. read or write (depending on desired results) 5. channel 1 or 3 (depending on jumper setting on Voice Master) Bit settings for the control byte of the 8237. bits 7,6 = 00 demand mode 01 single mode 10 block mode 11 cascade mode bit 5 = 0 address increment 1 address decrement bit 4 = 0 no automatic reinitialize 1 automatic reinitialize bits 3,2 = 00 verify 01 write 10 read bits 1,0 = 00 channel 0 01 channel 1 10 channel 2 11 channel 3 ---------------------------------------------------------------------- DMA BUFFER - 20-BIT SEGMENT ADDRESS Bits 2 and 3 of the byte written to the 8237 DMA CONTROLLER determine whether DMA recording or playback will be performed. Both DMA i/o directions require that the start address of a data buffer be output to the DMA ADDRESS REGISTER and the physical page be outp to the DMA PAGE REGISTER. EXAMPLE : This example uses a long named temp_address to store the 20 bit address of a Test_Buffer of char. First the page address of Test_Buffer is outp to the DMA PAGE REGISTER. The remaining 16 bit address is outp to the DMA ADDR REGISTER. Channel 1 is the active settings of the Voice Master for this example. /* Get 20 bit address of test buffer */ temp_address = ((long)FP_SEG(Test_Buffer))<<4) + (long)FP_OFF(Test_Buffer); /* Output segment page address of test buffer to the DMA PAGE REGISTER // for channel 1. */ outp( DMA_CH1_PAGE_REGISTER, (unsigned char)(temp_address >> 16) ); /* Set the address of the test buffer. outp LSB then MSB. */ outp( DMA_CLEAR_LSB_MSB, 0x00 ); outp( DMA_CH1_ADDR_REGISTER, (unsigned char)(temp_address) ); outp( DMA_CH1_ADDR_REGISTER, (unsigned char)(temp_address >> 8) ); ---------------------------------------------------------------------- DMA BUFFER - CURRENT BUFFER SIZE The size of the current buffer being used with DMA i/o should be output to the DMA COUNT REGISTER. Special considerations need to be made for buffers that cross page boundaries. EXAMPLE : This example assumes that the length of Test_Buffer is stored in a variable named Test_Buffer_Count. Since the DMA predecrements this count before a byte is processed we add 1 to the count before it is outp to the DMA COUNT REGISTER. Channel 1 is the active settings of the Voice Master for this example. This example does not check to see if the length of the buffer exceeds the available length left before the page boundary. /* Set word count on DMA channel 1. */ outp( DMA_CLEAR_LSB_MSB, 0x00 ); outp( DMA_CH1_COUNT_REGISTER, Test_Buffer_Count + 1 ); outp( DMA_CH1_COUNT_REGISTER, 0x00 ); /* Enable 8237 DMA on the mother board */ outp( DMA_MASK_REGISTER , DMA_CH1); ---------------------------------------------------------------------- IMPORTANT PROGRAMMING CONSIDERATIONS 1. Disabling and enabling of the DMA subsystem can cause an IRQ to fire off. 2. When the terminal count is reached on the 8237 DMA controller the DACK line on the Voice Master goes high. To set this line to low and thus allow the next interrupt to occur you must outp( (vmdma_base_port + VMDMA_CLEAR_IRQ_OFFSET), 0) directly before issuing an outp(0x20,0x20) in your interrupt handler.